package Commons.WebServiceClient;

import Commons.Logging.Log;
import java.io.Serializable;
import java.util.HashMap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author drag0nman
 */
@XmlRootElement()
@XmlAccessorType(XmlAccessType.FIELD)
public class VectorClock extends Log implements Serializable {

    private HashMap<Integer, Integer> vectorClock;

    public VectorClock() {
        super();
        vectorClock = new HashMap<Integer, Integer>();
    }

    public VectorClock(String tipoEntita,String idEntita,String operazione,String timestamp) {
        super(tipoEntita,idEntita,operazione,timestamp);
        vectorClock = new HashMap<Integer, Integer>();
    }

    public HashMap<Integer, Integer> getVectorClock() {
        return vectorClock;
    }

    public void setVectorClock(HashMap<Integer, Integer> vectorClock) {
        this.vectorClock = vectorClock;
    }

    public void incrementaVC(int posizione){
        if (vectorClock.containsKey(posizione))
            vectorClock.put(posizione, vectorClock.get(posizione)+1);
        else
            vectorClock.put(posizione, 1);
    }

	/**
	 * Operazione di confronto dei vectorclock.
	 * Restituisce uno fra quattro possibili valori
	 * che indicano come il vectorclock su cui è chiamato il metodo
         * è in relazione con il vectorclock passato come parametro.
         * Denominando come vc1 e vc2 rispettivamente l'oggetto su cui il metodo è invocato
         * e l'oggetto passato come parametro con cui effettuare il confronto, avremo i seguenti risultati:
	 * </ul>
         *      <li>ConfrontoVectorClock.MAGGIORE		se vc1 > vc2.</li>
	 *      <li>ConfrontoVectorClock.UGUALE			se vc1 = vc2.</li>
	 *      <li>ConfrontoVectorClock.MINORE			se vc1 < vc2.</li>
	 *      <li>ConfrontoVectorClock.CONCORRENTE		se vc1 <> vc2.</li>
         * </ul>
	 *
	 * @param vc vectorclock con cui effetturare il confronto.
	 *
	 * @return Valore dell'enumeratore ConfrontoVectorClock che indica la relazione
	 * che intercorre tra il vectorclock su cui è chiamato il metodo
         * e il vectorclock passato come parametro
	 */
	public ConfrontoVectorClock confronta(VectorClock vc)
	{
            HashMap<Integer,Integer> vc1 = this.getVectorClock();
            HashMap<Integer,Integer> vc2 = vc.getVectorClock();
		// Inizialmente assumo che siano vere tutte le possibilità
		// nel confronto del singolo elemento dei due Vectorclockvector
		boolean primoUgualeAlSecondo	 = true;
		boolean primoMaggioreDelSecondo = true;
		boolean primoMinoreDelSecondo = true;

		// Ciclo su tutti gli elementi del primo vectorclock
		for (int posizione : vc1.keySet())
		{
			// Se il singolo elemento del primo vectorclock
			// è presente anche nel secondo vectorclock
			// faccio il confronto dei due.
			if (vc2.containsKey(posizione))
			{
				// Se l'elemento del primo vectorclock
				// è minore dell'elemento del secondo vectorclock,
				// allora pongo a falso le possibilità di uguale e maggiore
				if (vc1.get(posizione) < vc2.get(posizione))
				{
					primoUgualeAlSecondo	 = false;
					primoMaggioreDelSecondo = false;
				}

				// Se l'elemento del primo vectorclock
				// è maggiore dell'elemento del secondo vectorclock,
				// allora pongo a falso le possibilità di uguale e minore
				if (vc1.get(posizione) > vc2.get(posizione))
				{
					primoUgualeAlSecondo	 = false;
					primoMinoreDelSecondo = false;
				}
			}
			// Se l'elemento del primo vectorclock
			// non è presente nel secondo vectorclock,
			// assumo che esso sia presente nel secondo vectorclock con valore zero,
			// e pertanto pongo a falso le possibilità di uguale e minore
			else if (vc1.get(posizione) != 0)
			{
				primoUgualeAlSecondo	 = false;
				primoMinoreDelSecondo = false;
			}
		}

		// Ciclo su tutti gli elementi del secondo vectorclock
		for (int posizione : vc2.keySet())
		{
			// Restano da confrontare solo gli elementi del secondo vectorclock
			// che non sono presenti all'interno del primo vectorclock;
			// pertanto, se l'elemento del secondo vectorclock non è presente nel primo
			// e il suo valore è diverso da zero,
			// allora pongo a falso le possibilità di uguale e maggiore
			if (!vc1.containsKey(posizione) && (vc2.get(posizione) != 0))
			{
				primoUgualeAlSecondo	 = false;
				primoMaggioreDelSecondo = false;
			}
		}

		// Restituisco il valore di ritorno
		// coerentemente alle informazioni ottenute
		if (primoUgualeAlSecondo)
		{
			return ConfrontoVectorClock.UGUALE;
		}
		else if (primoMaggioreDelSecondo && !primoMinoreDelSecondo)
		{
			return ConfrontoVectorClock.MAGGIORE;
		}
		else if (primoMinoreDelSecondo && !primoMaggioreDelSecondo)
		{
			return ConfrontoVectorClock.MINORE;
		}
		else
		{
			return ConfrontoVectorClock.UGUALE;
		}
	}

}
